﻿package org.hive.managers.plugin
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import org.hive.events.LoaderSetEvent;
	import org.hive.events.LoadManagerEvent;
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.utils.Dictionary;
	import org.hive.managers.StateManager;
	import org.hive.sequence.Sequence;
	
	import flash.events.IEventDispatcher;
	import org.hive.managers.Manager;
	import org.hive.data.*

	
	public final class LoadManager extends Manager
	{
        /**
        *
        */
		private static var __LOADERSETS				:Dictionary = new Dictionary( true );
		private static var __LOADERSETS_BY_NAME		:Dictionary = new Dictionary( true );
		
		private static var __LOADERS				:Dictionary = new Dictionary( true );
		private static var __LOADERS_BY_NAME		:Dictionary = new Dictionary( true );
		private static var __LOADERS_BY_CONTENT		:Dictionary = new Dictionary( true );
		

		
		public static var initialized:Boolean = false;
		
		public static function init():void
		{
			if( !initialized ) {
				trace( "LoadManager :: initializing" );
				
				//_____________ Register Object :: LoaderData
				function loaderDataFunc( action:*, sequence:Sequence, positionInSequence:int ):void {
					LoadManager.add( action );
				}
				StateManager.registerAction(LoaderData, loaderDataFunc);
				
				//_____________ Register Object :: LoaderSet
				function loaderSetFunc( action:*, sequence:Sequence, positionInSequence:int ):void {
					LoadManager.loadSet( action );
				}
				StateManager.registerAction(LoaderSet, loaderSetFunc);
				
				StateManager.registerManager( LoadManager );
				
				LoadManager.addEventListener( LoadManagerEvent.ON_ELEMENT_ADDED, distributeLoaderElement, false, 0, true );
				
				initialized = true;
			}
		}
		
		
		public static function loadSet( loaderSet:LoaderSet ):void
		{
			loaderSet.addEventListener( LoaderSetEvent.ON_ELEMENT_ADDED, elementAdded, false, 0, true );
			loaderSet.addEventListener( LoaderSetEvent.ON_COMPLETE, setComplete, false, 0, true );
			loaderSet.startLoad();
		}
		
		
		
		
		protected static var loaderElementLib	:Dictionary = new Dictionary(false);
		
		/**
        *
        * @param	definition		Registers the class definition to the loader library.
        * @param	callback		Registers the callback function with the class definition: callback( loaderElement:* ).
        */
		
		public static function registerLoaderElement( definition:Class, callback:Function )
		{
			loaderElementLib[ definition ] = callback;
		}
		
		private static function distributeLoaderElement( e:LoadManagerEvent ):void
		{
			for ( var conditionalClass:* in loaderElementLib ) {
				if ( e.element is conditionalClass ) {
					loaderElementLib[ conditionalClass ]( e.element );
				}
			}
		}
		
		
		
		//HANDLERS
		private static function elementAdded( e:LoaderSetEvent ):void
		{
			dispatchEvent( new LoadManagerEvent( LoadManagerEvent.ON_ELEMENT_ADDED, e.percent, e.element ) );
		}
		
		private static function setComplete( e:LoaderSetEvent ):void
		{
			e.currentTarget.removeEventListener( LoaderSetEvent.ON_ELEMENT_ADDED, elementAdded );
			e.currentTarget.removeEventListener( LoaderSetEvent.ON_COMPLETE, setComplete );
		}
				
		
		// MANAGEMENT
		public static function addLoaderSet( loaderSet:LoaderSet ):void
		{
			__LOADERSETS_BY_NAME[ loaderSet.name ] = loaderSet;
			__LOADERSETS[ loaderSet ] = loaderSet.name;
		}
		
		public static function add( ...args ):void
		{
			for (var i:Number = 0; i < args.length; i++) {
				if( args[i] is LoaderData ){
					__LOADERS_BY_CONTENT[ args[i].contentLoaderInfo ] = args[i];
				}
				else if( args[i] is SoundData || args[i] is URLData ){
					__LOADERS_BY_CONTENT[ args[i] ] = args[i];
				}
				__LOADERS_BY_NAME[ args[i].name ] = args[i];
				__LOADERS[ args[i] ] = args[i].name;
		    }
		}
		
		public static function remove( ldr:* ):void
		{
			delete __LOADERS[ ldr ];
			delete __LOADERS_BY_NAME[ ldr.name ];
			if( ldr is LoaderData ) delete __LOADERS_BY_CONTENT[ ldr.contentLoaderInfo ];
			else if( ldr is SoundData ) delete __LOADERS_BY_CONTENT[ ldr ];
			else if( ldr is URLData ) delete __LOADERS_BY_CONTENT[ ldr.data ];
		}
		
		public static function removeByName( ...names ):void
		{
			for (var i:Number = 0; i < names.length; i++) {
		        remove( getLoaderByName( names[i] ) )
		    }
		}
		
		public static function getLoaderByName( name:String ):*
		{
			return __LOADERS_BY_NAME[ name ];
		}
		
		public static function getLoaderByContent( info:* ):*
		{
			return __LOADERS_BY_CONTENT[ info ];
		}
		
		public static function getLoadersetByName( name:String ):*
		{
			return __LOADERSETS_BY_NAME[ name ];
		}
			
		
		//_________________________________________________________________________________________________ STATIC EVENT DISPATCHER METHODS
		protected static var disp:EventDispatcher;
		
		public static function addEventListener(p_type:String, p_listener:Function, p_useCapture:Boolean = false, p_priority:int = 0, p_useWeakReference:Boolean = false):void {
			if (disp == null) { disp = new EventDispatcher(); }
			disp.addEventListener(p_type, p_listener, p_useCapture, p_priority, p_useWeakReference);
		}
		
		public static function removeEventListener(p_type:String, p_listener:Function, p_useCapture:Boolean=false):void {
			if (disp == null) { return; }
			disp.removeEventListener(p_type, p_listener, p_useCapture);
		}
		
		public static function dispatchEvent(p_event:Event):void {
			if (disp == null) { return; }
			disp.dispatchEvent(p_event);
		}
		
	}
}